//
//  File Name   :   Directory.cpp
//  Description :   Directory implementation file.
//  Author      :   William McVicar
//  Mail        :   mcvicar.william@gmail.com
//

//  Precompiled Header
#include "CommonDefines.h"

//  Library Includes
#include "IFileSystem.h"

//  Local Includes
#ifdef PROTEIN_PLATFORM_IOS
#include <dirent.h>
#endif

//  This includes
#include "Directory.h"

//  Macros

//  Static Variables

//  Static Function Prototypes

//  Implementation

namespace Protein
{

Directory::Directory()
{
	//
}

Directory::Directory( const std::string& _krPath )
: m_Path( _krPath )
{
	//
}

Directory::Directory( const c8* _szPath )
: m_Path( _szPath )
{
	//
}

Directory::Directory( const Directory& other )
: m_Path( other.m_Path )
, m_Subdirectories( other.m_Subdirectories )
{
	//
}

Directory& Directory::operator=( const Directory& rhs )
{
	m_Path = rhs.m_Path;
	m_Subdirectories.reserve(rhs.GetSubDirectories().size());
	m_Subdirectories = rhs.m_Subdirectories;

	return *this;
}

Directory::~Directory()
{
	//
}

bool Directory::operator==( const Directory& other )
{
	return m_Path == other.m_Path;
}

void Directory::AddSubDirectory( const std::string& _krSubDirectory, bool _bAppendParent )
{
	char buff[ PROTEIN_MAX_PATH ];

	if( _bAppendParent )
	{
		strcpy( buff, m_Path.c_str() );
		strcat( buff, IFileSystem::sm_szPathSeparator );
		strcat( buff, _krSubDirectory.c_str() );
	}
	else
	{
		strcpy( buff, _krSubDirectory.c_str() );
	}

	Directory subDir( buff );
	m_Subdirectories.push_back( subDir );
}

void Directory::AddSubDirectory( const c8* _szSubDirectory, bool _bAppendParent  )
{
	std::string path;

	if( _bAppendParent )
	{
		path = m_Path;
		path.append( IFileSystem::sm_szPathSeparator );
		path.append( _szSubDirectory );
	}
	else
	{
		path = _szSubDirectory;
	}

	Directory subDir( path );
	m_Subdirectories.push_back( subDir );
}

void Directory::ClearSubdirectories()
{
	m_Subdirectories.clear();
}

void Directory::AddSubDirectoriesRecursive( const std::string& _krSubDirectory, bool _bIsVirtual )
{
#if defined( PROTEIN_PLATFORM_WINDOWS )
	AddSubDirectoriesRecursiveWin32( _krSubDirectory, _bIsVirtual );
#elif defined( PROTEIN_PLATFORM_IOS )
	AddSubDirectoriesRecursiveIOS( _krSubDirectory, _bIsVirtual );
#endif
}

void Directory::AddSubDirectoriesRecursive( const c8* _szSubDirectory, bool _bIsVirtual )
{
	std::string subDir( _szSubDirectory );
	AddSubDirectoriesRecursive( subDir, _bIsVirtual );
}

void Directory::AddSubDirectoriesRecursive()
{
#if defined( PROTEIN_PLATFORM_WINDOWS )
	AddSubDirectoriesRecursiveWin32();
#elif defined( PROTEIN_PLATFORM_IOS )
	AddSubDirectoriesRecursiveIOS();
#endif	
}

#if defined( PROTEIN_PLATFORM_WINDOWS )
void Directory::AddSubDirectoriesRecursiveWin32( const std::string& _krSubDirectory, bool _bIsVirtual )
{
	HANDLE			hFind;
	WIN32_FIND_DATA FindFileData;

	std::wstringstream wstrstream;
	if( !_bIsVirtual )
		wstrstream << m_Path.c_str() << IFileSystem::sm_szPathSeparator;
	
	wstrstream  << _krSubDirectory.c_str() << IFileSystem::sm_szPathSeparator << '*';
	std::wstring wstr = wstrstream.str();
	hFind = FindFirstFile( wstr.c_str(), &FindFileData );

	if( hFind != INVALID_HANDLE_VALUE && ( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
	{
		AddSubDirectory( _krSubDirectory, !_bIsVirtual );
		do
		{
			if( !wcschr( FindFileData.cFileName, L'.' ) )
			{
				c8 buf[ PROTEIN_MAX_PATH ];
				wcstombs( buf, FindFileData.cFileName, sizeof( c16 ) * wcslen( FindFileData.cFileName ) );
				m_Subdirectories.back().AddSubDirectoriesRecursive( buf, false );
			}
		}
		while( FindNextFile( hFind, &FindFileData ) );
	}
}

void Directory::AddSubDirectoriesRecursiveWin32()
{
	HANDLE			hFind;
	WIN32_FIND_DATA FindFileData;

	std::wstringstream wstrstream;
	wstrstream << m_Path.c_str() << IFileSystem::sm_szPathSeparator << '*';
	std::wstring wstr = wstrstream.str();
	hFind = FindFirstFile( wstr.c_str(), &FindFileData );

	if( hFind != INVALID_HANDLE_VALUE && ( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
	{
		do
		{
			if( !wcschr( FindFileData.cFileName, L'.' ) )
			{
				c8 buf[ PROTEIN_MAX_PATH ];
				wcstombs( buf, FindFileData.cFileName, sizeof( c16 ) * wcslen( FindFileData.cFileName ) );
				this->AddSubDirectoriesRecursive( buf, false );
			}
		}
		while( FindNextFile( hFind, &FindFileData ) );
	}
}

#elif defined( PROTEIN_PLATFORM_IOS )
void Directory::AddSubDirectoriesRecursiveIOS( const std::string& _krSubDirectory, bool _bIsVirtual )
{
	c8 buf[ PROTEIN_MAX_PATH ];
	strcpy( buf, m_Path.c_str() );
	strcat(buf, IFileSystem::sm_szPathSeparator );
	strcat(buf, _krSubDirectory.c_str() );
	
	DIR* dir = opendir(buf);
    if (!dir)
        return;
	
	AddSubDirectory( _krSubDirectory, !_bIsVirtual );
	
    dirent* entry;
    while ((entry = readdir(dir)) != NULL )
    {
		if( entry->d_type != DT_DIR )
			continue;//dont allow directories with .'s in their names
		
		if( strchr( entry->d_name, '.' ) )
			continue;
		
        DIR * dirtest = opendir(buf);
        if (dirtest)
        {
            closedir(dirtest);
			m_Subdirectories.back().AddSubDirectoriesRecursiveIOS( std::string( entry->d_name ), false );
        }
    }

    closedir(dir);
}
void Directory::AddSubDirectoriesRecursiveIOS()
{
	c8 buf[ PROTEIN_MAX_PATH ];
	strcpy( buf, m_Path.c_str() );
	//strcat(buf, IFileSystem::sm_szPathSeparator );
	
	DIR* dir = opendir(buf);
    if (!dir)
        return;

    dirent* entry;
    while ((entry = readdir(dir)) != NULL )
    {
		if( entry->d_type != DT_DIR )
			continue;//dont allow directories with .'s in their names
		
		if( strchr( entry->d_name, '.' ) )
			continue;
		
        DIR * dirtest = opendir(buf);
        if (dirtest)
        {
            closedir(dirtest);
			this->AddSubDirectoriesRecursiveIOS( std::string( entry->d_name ), false );
        }
    }

    closedir(dir);
}
#endif

}